package com.meiyou.service.impl;


import com.meiyou.constant.JwtClaimsConstant;
import com.meiyou.constant.MessageConstant;
import com.meiyou.context.BaseContext;
import com.meiyou.dto.UpdateUserDto;
import com.meiyou.dto.UserLoginDto;
import com.meiyou.dto.UserRegisterDto;
import com.meiyou.entity.User;
import com.meiyou.exception.*;
import com.meiyou.mapper.UserMapper;
import com.meiyou.properties.JwtProperties;
import com.meiyou.properties.MailProperties;
import com.meiyou.service.UserService;
import com.meiyou.utils.CommonUtil;
import com.meiyou.utils.JwtUtil;
import com.meiyou.vo.UserInfoVo;
import com.meiyou.vo.UserLoginVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.MailSendException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MailProperties mailProperties;

    @Autowired
    private JavaMailSender javaMailSender;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private JwtProperties jwtProperties;

    @Value("${my.up-image.path}")
    private String basePath;

    /**
     * 注册
     *
     * @param userRegisterDto
     */
    @Override
    public void register(UserRegisterDto userRegisterDto) {

        // 根据邮箱获取保存在redis里面的验证码
        Object codeSession = redisTemplate.opsForValue().get(userRegisterDto.getEmail());

        if (codeSession != null && codeSession.equals(userRegisterDto.getCode())) {

            // 判断该账号和邮箱是否已注册
            Integer count = userMapper.select(userRegisterDto);
            // 大于0说明已注册
            if (count > 0) {
                throw new AccountOrEmailExistException(MessageConstant.ACCOUNT_EXIST);
            }

            User user = new User();
            // 将userRegisterDto的数据复制给user
            BeanUtils.copyProperties(userRegisterDto, user);
            // 将密码进行MD5加密
            user.setPassword(DigestUtils.md5DigestAsHex(userRegisterDto.getPassword().getBytes()));
            // 向用户表插入数据
            userMapper.insert(user);
        } else {
            throw new CodeErrorException(MessageConstant.CODE_ERROR);
        }
    }

    /**
     * 发送验证码
     *
     * @return
     */
    @Override
    public void sendCode(String email) {

        SimpleMailMessage message = new SimpleMailMessage();
        //随机数生成6位验证码
        String code = CommonUtil.VerifyCode(6);
        message.setFrom(mailProperties.getUsername());
        message.setTo(email);
        // 标题
        message.setSubject("小柚子");
        message.setText("【小柚子】你的验证码为：" + code + "，有效时间为5分钟(若不是本人操作，可忽略该条邮件)");// 内容
        try {
            // 发送验证码
//            javaMailSender.send(message);
            // 保存验证码到redis中
            log.info("验证码：" + code);
            redisTemplate.opsForValue().set(email, code, 5, TimeUnit.MINUTES);
        } catch (MailSendException e) {
            throw new EmailNotExist(MessageConstant.EMAIL_NOT_EXIST);
        } catch (Exception e) {
            throw new EmailNotExist(MessageConstant.CODE_SEND_FAIL);
        }
    }

    /**
     * 登录
     *
     * @param userLoginDto
     * @return
     */
    @Override
    public UserLoginVo login(UserLoginDto userLoginDto) {

        String username = userLoginDto.getUsername();
        String password = userLoginDto.getPassword();

        //1、根据用户名查询数据库中的数据
        User user = userMapper.getByUsername(username);

        //2、处理各种异常情况（用户名不存在、密码不对）
        if (user == null) {
            //账号不存在
            throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
        }

        //密码比对
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!password.equals(user.getPassword())) {
            //密码错误
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }

        //登录成功后，生成jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID, user.getId());
        String token = JwtUtil.createJWT(
                jwtProperties.getSecretKey(),
                jwtProperties.getTtl(),
                claims);

        // 创建userLoginVo对象
        UserLoginVo userLoginVo = UserLoginVo.builder()
                .token(token)
                .build();

        return userLoginVo;
    }

    /**
     * 忘记密码，修改密码
     *
     * @param id
     * @param password
     * @return
     */
    @Override
    public void forgetPassword(Long id, String password) {

        // 加密密码
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        User user = User.builder()
                .id(id)
                .password(password)
                .build();
        userMapper.update(user);
    }

    /**
     * 验证验证码是否正确、邮箱是否已注册
     *
     * @param map
     * @return
     */
    @Override
    public Long verifyCode(Map map) {

        // 根据邮箱获取保存在redis里面的验证码
        Object codeSession = redisTemplate.opsForValue().get(map.get("email"));

        if (codeSession != null && codeSession.equals(map.get("code"))) {
            // 查询
            Long userId = userMapper.getByUserIdEmail(map.get("email").toString());

            if (userId == null) {
                throw new EmailNotExist(MessageConstant.EMAIL_NOT_EXIST);
            }
            return userId;
        }
        throw new CodeErrorException(MessageConstant.CODE_ERROR);
    }

    /**
     * 修改用户信息
     *
     * @param updateUserDto
     * @return
     */
    @Override
    public void updateUserInfo(UpdateUserDto updateUserDto) {

        // 如果是修改用户头像则要把本地图片删除了
        if (updateUserDto.getAvatar() != null) {
            // 查询用户旧头像地址
            String avatar = userMapper.selectAvatar(BaseContext.getCurrentId());
            // 查询到就删除
            if (avatar != null) CommonUtil.deleteFile(basePath + avatar);
        }

        User user = new User();
        BeanUtils.copyProperties(updateUserDto, user);
        user.setId(BaseContext.getCurrentId());
        userMapper.update(user);
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    @Override
    public UserInfoVo getUserInfo() {

        UserInfoVo userInfoVo = userMapper.getByUserId(BaseContext.getCurrentId());

        return userInfoVo;
    }
}
